package efg;

import interfacesFerrovia.DefsGlobais.TipoAtributo;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * Representa um trecho na malha ferroviaria
 * 
 */
public class Track extends RailwayElement {

	private Map<Train, Direction> passingTrains;
	private Map<Train, Set<Train>> conflicts;

	public Track(String id, Railway r) {
		super(r, id);
		assert (getId() != null);
		assert (r != null);
		this.passingTrains = new HashMap<Train, Direction>();
		this.conflicts = new HashMap<Train, Set<Train>>();
	}

	/**
	 * Registra uma composicao e o sentido pelo qual ela vai passar no trecho,
	 * detectando possiveis casos de colisao frontal
	 * 
	 * @param passingTrain
	 *            Composicao que vai passar
	 * @param direction
	 *            Direcao
	 */
	public synchronized void registerTrain(Train passingTrain,
			Direction direction) {
		Set<Train> conflictedTrains = new HashSet<Train>();
		conflicts.put(passingTrain, conflictedTrains);
		for (Entry<Train, Direction> entry : passingTrains.entrySet()) {
			if (!entry.getValue().equals(direction)) {
				conflictedTrains.add(entry.getKey());
			}
		}
		passingTrains.put(passingTrain, direction);
	}

	/**
	 * 
	 * @param train
	 *            Composicao a observar
	 * @return Lista de composicoes que podem colidir frontalmente com essa
	 *         neste trecho
	 */
	public Set<Train> getConflicts(Train train) {
		return new HashSet<Train>(conflicts.get(train));
	}

	public String getaSwitchId() {
		return (String) getAttribute(TipoAtributo.ID_TR_CH_A);
	}

	public String getbSwitchId() {
		return (String) getAttribute(TipoAtributo.ID_TR_CH_B);
	}

	public Integer getCompositionNumber() {
		return (Integer) getAttribute(TipoAtributo.N_COMPOSICOES);
	}

	public Float getLength() {
		return (Float) getStaticAttribute(TipoAtributo.DISTANCIA);
	}

	public Switch getaSwitch() {
		String id = getaSwitchId();
		if (id != null) {
			return (Switch) getElementById(id);
		}
		return null;
	}

	public Switch getbSwitch() {
		String id = getbSwitchId();
		if (id != null) {
			return (Switch) getElementById(id);
		}
		return null;
	}

	/**
	 * Retorna a chave a ser encontrada no fim deste trecho em um determinado
	 * sentido
	 * 
	 * @param direction
	 * @return
	 */
	public Switch getDestinySwitch(Direction direction) {
		assert (direction != null);
		if (direction.equals(Direction.A_TO_B)) {
			return getbSwitch();
		} else {
			return getaSwitch();
		}
	}

}
